import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

/**
 * An employee information dialog class.This dialog class is just a subclass of the Dialog.
 * 
 * @author zhongnanhai
 *
 */
public class EmployeeDialog extends Dialog{
	/**The employee information that this dialog would return.*/
	private Employee employee = null;
	/**Productivity table.*/
	private Table productivityTable;
	/**All of the productivities*/
	private Map<Integer,Float> productivities = null;
	/**All of the roles*/
	private ArrayList<Integer> roles = null;
	/**
	 * The constructor with a default style.
	 * @param parent its parent window
	 */
	public EmployeeDialog(Shell parent){
		this(parent,SWT.DIALOG_TRIM | SWT.CLOSE | SWT.PRIMARY_MODAL);
	}
	/**
	 * The constructor of employeeDailog.
	 * 
	 * @param parent its parent window
	 * @param style its specific style
	 */
	public EmployeeDialog(Shell parent, int style) {
		super(parent, style);
		// TODO Auto-generated constructor stub
	}
	/**
	 * The open method of a dialog class.
	 * @return an employee object
	 */
	public Employee open(){
		Shell shell = new Shell(getParent(),getStyle());
		if(employee == null) shell.setText("Add a new employee");
		else shell.setText("Edit "+employee.getemployeename());
		createContents(shell);
		shell.setSize(255, 338);
		int x = getParent().getBounds().x + (getParent().getBounds().width - shell.getBounds().width)/2;
		int y = getParent().getBounds().y + (getParent().getBounds().height - shell.getBounds().height)/2;
		shell.setLocation(x,y);
		shell.open();
		Display display = getParent().getDisplay();
		while(!shell.isDisposed()){
			if(!display.readAndDispatch())
				display.sleep();
		}
		return employee;
	}
	/**
	 * Set the employee information of this dialog.
	 * @param employee the employee object
	 */
	public void setemployee(Employee employee){
		this.employee = employee;
	}
	/**
	 * Create all of the contents/controls of this dialog.
	 * @param shell the dialog window
	 */
	private void createContents(final Shell shell){
		shell.setLayout(new FormLayout());
		int gap = 3;
		//add all necessary controls and layout them with proper position
		Label nameLbl = new Label(shell,SWT.RIGHT);
		nameLbl.setText("Name:");
		FormData data = new FormData();
		data.top = new FormAttachment(0,gap);
		data.right = new FormAttachment(30,0);
		nameLbl.setLayoutData(data);
		final Text nameTxt = new Text(shell,SWT.BORDER);
		data = new FormData();
		data.left = new FormAttachment(nameLbl);
		data.right = new FormAttachment(80,0);
		nameTxt.setLayoutData(data);
		Label dscribLbl = new Label(shell,SWT.RIGHT);
		dscribLbl.setText("Description:");
		data = new FormData();
		data.top = new FormAttachment(nameTxt,gap);
		data.right = new FormAttachment(30,0);
		dscribLbl.setLayoutData(data);
		final Text dscribTxt = new Text(shell,SWT.BORDER);
		data = new FormData();
		data.top = new FormAttachment(nameTxt);
		data.left = new FormAttachment(dscribLbl);
		data.right = new FormAttachment(80,0);
		dscribTxt.setLayoutData(data);
		Label salaryLbl = new Label(shell,SWT.RIGHT);
		salaryLbl.setText("Salary:");
		data = new FormData();
		data.top = new FormAttachment(dscribTxt,gap);
		data.right = new FormAttachment(30,0);
		salaryLbl.setLayoutData(data);
		final Text salaryTxt = new Text(shell,SWT.BORDER);
		data = new FormData();
		data.top = new FormAttachment(dscribTxt);
		data.left = new FormAttachment(salaryLbl);
		data.right = new FormAttachment(80,0);
		salaryTxt.setLayoutData(data);
		Label timezoneLbl = new Label(shell,SWT.RIGHT);
		timezoneLbl.setText("Time Zone:");
		data = new FormData();
		data.top = new FormAttachment(salaryTxt,gap);
		data.right = new FormAttachment(30,0);
		timezoneLbl.setLayoutData(data);
		final Combo timezoneList = new Combo(shell,SWT.DROP_DOWN | SWT.READ_ONLY);
		timezoneList.setItems(AllBasicData.timeZones);
		data = new FormData();
		data.top = new FormAttachment(salaryTxt);
		data.left = new FormAttachment(timezoneLbl);
		data.right = new FormAttachment(85,0);
		timezoneList.setLayoutData(data);
		Label cultureLbl = new Label(shell,SWT.RIGHT);
		cultureLbl.setText("Country:");
		data = new FormData();
		data.top = new FormAttachment(timezoneList,gap);
		data.right = new FormAttachment(30,0);
		cultureLbl.setLayoutData(data);
		final Combo cultureList = new Combo(shell,SWT.DROP_DOWN | SWT.READ_ONLY);
		for(int i = 0;i<AllBasicData.countries.length;i++)
			cultureList.add(AllBasicData.countries[i].replace('_', ' '));
		data = new FormData();
		data.top = new FormAttachment(timezoneList);
		data.left = new FormAttachment(cultureLbl);
		data.right = new FormAttachment(85,0);
		cultureList.setVisibleItemCount(10);
		cultureList.setLayoutData(data);
						
		Label skillsLbl = new Label(shell,SWT.RIGHT);
		skillsLbl.setText("Skill and \nProductivity:");
		data = new FormData();
		data.top = new FormAttachment(cultureList,gap);
		data.right = new FormAttachment(30,0);
		skillsLbl.setLayoutData(data);
		productivityTable = new Table(shell,SWT.BORDER);
		productivityTable.setHeaderVisible(true);
		productivityTable.setLinesVisible(true);
		TableColumn[] columns = new TableColumn[2];
		columns[0] = new TableColumn(productivityTable,SWT.NONE);
		columns[0].setText("Skill");
		columns[1] = new TableColumn(productivityTable,SWT.NONE);
		columns[1].setText("Productivity");
		columns[0].pack();columns[1].pack();
		data = new FormData();
		data.top = new FormAttachment(cultureList);
		data.left = new FormAttachment(skillsLbl);
		data.right = new FormAttachment(80,0);
		data.bottom = new FormAttachment(70,0);
		productivityTable.setLayoutData(data);
		Button pdAddBtn = new Button(shell,SWT.LEFT | SWT.ARROW);
		data = new FormData();
		data.top = new FormAttachment(cultureList);
		data.left = new FormAttachment(productivityTable);
		data.right = new FormAttachment(80,16);
		pdAddBtn.setLayoutData(data);
		pdAddBtn.setToolTipText("Add a new skill and set its productivity");
		
		Label employeeRolesLbl = new Label(shell,SWT.RIGHT);
		employeeRolesLbl.setText("Act Roles:");
		data = new FormData();
		data.right = new FormAttachment(30,0);
		data.top = new FormAttachment(productivityTable,gap);
		employeeRolesLbl.setLayoutData(data);
		final List employeeRolesList = new List(shell,SWT.BORDER|SWT.SINGLE|SWT.VERTICAL);
		data = new FormData();
		data.left = new FormAttachment(employeeRolesLbl);
		data.right = new FormAttachment(80,0);
		data.top = new FormAttachment(productivityTable);
		data.bottom = new FormAttachment(92);
		employeeRolesList.setLayoutData(data);
		Button rlAddBtn = new Button(shell,SWT.RIGHT |SWT.ARROW);
		data = new FormData();
		data.top = new FormAttachment(productivityTable);
		data.left = new FormAttachment(employeeRolesList);
		rlAddBtn.setLayoutData(data);
		rlAddBtn.setToolTipText("Manage employee's own roles");
		
		Button addBtn = new Button(shell,SWT.PUSH);
		data = new FormData();
		data.top = new FormAttachment(employeeRolesList,gap);
		data.left = new FormAttachment(10,0);
		data.right = new FormAttachment(45,0);
		data.bottom = new FormAttachment(100,0);
		addBtn.setLayoutData(data);
		Button cancelBtn = new Button(shell,SWT.PUSH);
		cancelBtn.setText("Cancel");
		data = new FormData();
		data.top = new FormAttachment(employeeRolesList,gap);
		data.left = new FormAttachment(55,0);
		data.right = new FormAttachment(90,0);
		data.bottom = new FormAttachment(100,0);
		cancelBtn.setLayoutData(data);
		
		//Set display different showing text of all the controls in different condition:
		//edit or create?
		if(employee == null){//create new employee
			nameTxt.setText("");
			dscribTxt.setText("");
			salaryTxt.setText("");
			timezoneList.select(-1);
			cultureList.select(-1);
			productivityTable.clearAll();
			employeeRolesList.removeAll();
			addBtn.setText("Add");
		}else{//modify an existed employee
			nameTxt.setText(employee.getemployeename());
			dscribTxt.setText(employee.getemployeedescription());
			salaryTxt.setText(employee.getSalary()+"");
			timezoneList.select(employee.getTimeZone());
			cultureList.select(employee.getCountry());
			productivityTable.clearAll();
			if(employee.getProductivity().size()>0){
				for(Integer key:employee.getProductivity().keySet()){
					TableItem item = new TableItem(productivityTable,SWT.NONE);
					item.setText(0, AllBasicData.skills[key]);
					item.setText(1, employee.getProductivity().get(key).toString());
				}
			}
			employeeRolesList.removeAll();
			if(employee.getRoles().size()>0){
				String[] items = new String[employee.getRoles().size()];
				int i = 0;
				for(Integer index:employee.getRoles()){
					items[i] = AllBasicData.roles[index];
					i ++;
				}
				employeeRolesList.setItems(items);
			}
			addBtn.setText("Modify");
		}
		if(employee == null){
			productivities = new HashMap<Integer,Float>();
			roles = new ArrayList<Integer>();
		}else{
			productivities = employee.getProductivity();
			roles = employee.getRoles();
		}
		//add necessary actions to its corresponding control
		pdAddBtn.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				SkillDialog dialog = new SkillDialog(shell);
				dialog.open();
				productivityTable.setRedraw(false);
				if(dialog.getSkillId()!=-1 && dialog.getProductivity() > 0.0){
					if(productivities.containsKey(dialog.getSkillId())){
						Utilities.showMessage(shell,SWT.ICON_QUESTION,"employee already has this skill,\n" +
								"do you want to change its productivity?");
						productivities.put(dialog.getSkillId(), dialog.getProductivity());
						TableItem item = productivityTable.getItem(skillIdToTableIndex(dialog.getSkillId()));
						item.setText(1, dialog.getProductivity()+"");
					}else{
						TableItem item = new TableItem(productivityTable,SWT.NONE);
						item.setText(0, AllBasicData.skills[dialog.getSkillId()]);
						item.setText(1,dialog.getProductivity()+"");
						
						productivities.put(dialog.getSkillId(), dialog.getProductivity());
					}
				}
				productivityTable.setRedraw(true);
			}
		});
		rlAddBtn.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				final ArrayList<String> roleArray = new ArrayList<String>();
				final Shell listShell = new Shell(shell,SWT.CLOSE);
				listShell.setLayout(new FillLayout());
				final Table roleList = new Table(listShell,SWT.CHECK);
				for(int i=0;i<AllBasicData.roles.length;i++){
					TableItem item = new TableItem(roleList,SWT.NONE);
					item.setText(AllBasicData.roles[i]);
				}
				if(roles != null && roles.size()>0){
					for(Integer index : roles)
						roleList.getItem(index).setChecked(true);
				}
				listShell.pack();
				int x = shell.getBounds().x + shell.getBounds().width;
				int y = shell.getBounds().y + shell.getBounds().height - listShell.getBounds().height;
				listShell.setLocation(x,y);
				listShell.open();
				listShell.addDisposeListener(new DisposeListener(){
					@Override
					public void widgetDisposed(DisposeEvent e) {
						// TODO Auto-generated method stub
						roles.clear();
						roleArray.clear();
						for(TableItem item:roleList.getItems()){
							if(item.getChecked()){
								roleArray.add(item.getText());
								roles.add(roleList.indexOf(item));
							}
						}
						String[] items = new String[roleArray.size()];
						roleArray.toArray(items);
						employeeRolesList.setRedraw(false);
						employeeRolesList.setItems(items);
						employeeRolesList.setRedraw(true);
					}
					
				});
			}
		});
		addBtn.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				int salary = 0;
				if(nameTxt.getText().trim().isEmpty()){
					Utilities.showMessage(shell,SWT.ICON_ERROR,"Please input the employee name");
					return;
				}else if(dscribTxt.getText().trim().isEmpty()){
					Utilities.showMessage(shell,SWT.ICON_ERROR,"Please input some description of this employee");
					return;
				}else if(salaryTxt.getText().trim().isEmpty()){
					Utilities.showMessage(shell,SWT.ICON_ERROR,"Please set the employee's salary");
					return;
				}else{
					if(!salaryTxt.getText().trim().isEmpty()){
						try{
							salary = Integer.parseInt(salaryTxt.getText().trim());
						}catch(Exception ept){
							Utilities.showMessage(shell,SWT.ICON_ERROR,"Please input a correct number of his salary");
							return;
						}
					}
					if(timezoneList.getSelectionIndex()<0){
						Utilities.showMessage(shell,SWT.ICON_ERROR,"Please select a timezone for this employee");
						return;
					}
					if(cultureList.getSelectionIndex() < 0){
						Utilities.showMessage(shell,SWT.ICON_ERROR,"Please select a culture type for this employee");
						return;
					}
					if(productivityTable.getItemCount() == 0){
						Utilities.showMessage(shell,SWT.ICON_QUESTION,"Are you sure that this employee does not have any skill?");
					}
					if(employeeRolesList.getItemCount() == 0){
						Utilities.showMessage(shell,SWT.ICON_QUESTION,"Are you sure that this employee does not act any role?");
					}
				}
				boolean isNew = true;
				if(employee == null){
					isNew = true;
					employee = new Employee();
				}else{
					isNew = false;
				}
				employee.setemployeename(nameTxt.getText().trim());
				employee.setemployeedescription(dscribTxt.getText().trim());
				employee.setSalary(salary);
				employee.setTimeZone(timezoneList.getSelectionIndex());
				employee.setCountry(cultureList.getSelectionIndex());
				employee.setProductivity(productivities);
				employee.setRoles(roles);
				
				if(isNew){
					Utilities.showMessage(shell,SWT.ICON_INFORMATION,"A new employee has been created.");
				}else{
					Utilities.showMessage(shell,SWT.ICON_INFORMATION,"The employee has been modified.");
				}
				shell.dispose();
			}
		});
		cancelBtn.addSelectionListener(new SelectionAdapter(){
			public void widgetSelected(SelectionEvent e){
				shell.dispose();
			}
		});
	}
	/**
	 * Giving a skill id, find its index in the productivity table.
	 * @param skillId skill id
	 * @return the index of this skill;if none,-1
	 */
	private int skillIdToTableIndex(int skillId){
		if(productivityTable.getItemCount()>0){
			for(int i=0;i<productivityTable.getItems().length;i++){
				if(productivityTable.getItem(i).getText(0).equals(AllBasicData.skills[skillId])){
					return i;
				}
			}
			return -1;
		}else{
			return -1;
		}
	}
	public static void main(String[] args) throws Exception{
		Display display = new Display();
		Shell shell = new Shell(display);
		new EmployeeDialog(shell,SWT.DIALOG_TRIM).open();
		while(!shell.isDisposed()){
			if(!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

}
